# Copyright (C) 2006-2008 by Sergio Pistone
# sergio_pistone@yahoo.com.ar
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

require File.expand_path( File.dirname( __FILE__ ) + "/../utils/strings" )
require File.expand_path( File.dirname( __FILE__ ) + "/../utils/xmlhash" )
require File.expand_path( File.dirname( __FILE__ ) + "/../i18n/i18n" )
require File.expand_path( File.dirname( __FILE__ ) + "/../gui/gui" )
require File.expand_path( File.dirname( __FILE__ ) + "/pluginadapter" )
require File.expand_path( File.dirname( __FILE__ ) + "/plugins" )
require File.expand_path( File.dirname( __FILE__ ) + "/amarok" )

require "uri"

module WikiPluginAdapter

	# Hack to make module methods become class methods when the module gets included
	def WikiPluginAdapter.included( including )
		if including.is_a?( Class )
			including.extend( ClassMethods ) # adds class methods
		else # including.is_a?( Module )
			including::ClassMethods.append_class_methods( self )
		end
	end

	# Methods under this module will became class methods when the module gets included
	# Note: don't use def self.<method name> but just <method name>
	module ClassMethods
		def ClassMethods.append_class_methods( mod )
			include mod::ClassMethods
		end
	end

	include PluginAdapter

	@@MENU_ENTRY_ALBUM		= I18n.get( "amarok.wikiplugin.checkalbum" )
	@@MENU_ENTRY_SONG		= I18n.get( "amarok.wikiplugin.checksong" )
	@@MENU_UPLOAD_COVER		= I18n.get( "amarok.wikiplugin.uploadcover" )
	@@MENU_SUBMIT_CONTENT	= I18n.get( "amarok.wikiplugin.submitcontent" )


	def check_submit_conditions()

 		if @wpa_submit
			login( @wpa_username, @wpa_password, false )
		else
			logout()
		end

		if ! logged_in?
			@wpa_submit = false
		end

		if ! @wpa_submit || ! @wpa_review
			@wpa_prompt_no_lyrics = false
			@wpa_prompt_autogen = false
		end

	end

	def submit?()
		return @wpa_submit
	end

	def read_config( config_file )

		values = {
			"#{plugin_name}_submit"				=> nil,
			"#{plugin_name}_review"				=> nil,
			"#{plugin_name}_prompt_autogen"		=> nil,
			"#{plugin_name}_prompt_no_lyrics"	=> nil,
			"#{plugin_name}_username"			=> nil,
			"#{plugin_name}_password"			=> nil,
			"#{plugin_name}_cookie"				=> nil,
			"#{plugin_name}_last_auth_check"	=> nil,
			"#{plugin_name}_authorized"			=> nil,
		}

		XMLHash.read( config_file, values )

		@wpa_review = values["#{plugin_name}_review"] != "false"
		@wpa_submit = values["#{plugin_name}_submit"] == "true"
		@wpa_prompt_autogen = values["#{plugin_name}_prompt_autogen"] == "true"
		@wpa_prompt_no_lyrics = values["#{plugin_name}_prompt_no_lyrics"] == "true"
		@wpa_username = Strings.descramble( values["#{plugin_name}_username"] )
		@wpa_password = Strings.descramble( values["#{plugin_name}_password"] )

 		if @wpa_submit
			restore_session_params(
				@wpa_username,
				@wpa_password,
				values["#{plugin_name}_cookie"],
				values["#{plugin_name}_last_auth_check"].to_i(),
				values["#{plugin_name}_authorized"] == "true"
			)
		end

		check_submit_conditions()

	end

	def write_config( config_file )

		if @wpa_submit
			username, password, cookie, last_auth_check, authorized = get_session_params()
		else
			cookie, last_auth_check, authorized = nil, nil, nil
		end

		values = {
			"#{plugin_name}_submit"				=> @wpa_submit,
			"#{plugin_name}_review"				=> @wpa_review,
			"#{plugin_name}_prompt_autogen"		=> @wpa_prompt_autogen,
			"#{plugin_name}_prompt_no_lyrics"	=> @wpa_prompt_no_lyrics,
			"#{plugin_name}_username"			=> Strings.scramble( @wpa_username ),
			"#{plugin_name}_password"			=> Strings.scramble( @wpa_password ),
			"#{plugin_name}_cookie"				=> cookie,
			"#{plugin_name}_last_auth_check"	=> last_auth_check,
			"#{plugin_name}_authorized"			=> authorized,
		}

		XMLHash.write( config_file, values )

	end

	def configure()

		values = {
			"site_name"			=> site_name(),
			"review"			=> @wpa_review,
			"submit"			=> @wpa_submit,
			"prompt_autogen"	=> @wpa_prompt_autogen,
			"prompt_no_lyrics"	=> @wpa_prompt_no_lyrics,
			"username"			=> @wpa_username,
			"password"			=> @wpa_password
		}

		if GUI.show_wiki_plugin_dialog( values )
			@wpa_review = values["review"].to_s() != "false"
			@wpa_submit = values["submit"].to_s() == "true"
			@wpa_prompt_autogen = values["prompt_autogen"].to_s() == "true"
			@wpa_prompt_no_lyrics = values["prompt_no_lyrics"].to_s() == "true"
			@wpa_username = values["username"]
			@wpa_password = values["password"]
		end

		check_submit_conditions()

		if @wpa_submit
			add_custom_menu_item( @@MENU_UPLOAD_COVER )
			add_custom_menu_item( @@MENU_ENTRY_ALBUM )
			add_custom_menu_item( @@MENU_ENTRY_SONG )
		else
			remove_custom_menu_item( @@MENU_UPLOAD_COVER )
			remove_custom_menu_item( @@MENU_ENTRY_ALBUM )
			remove_custom_menu_item( @@MENU_ENTRY_SONG )
		end

		add_custom_checkeable_menu_item( @@MENU_SUBMIT_CONTENT, @wpa_submit )

	end

	def on_start()
		if @wpa_submit
			add_custom_menu_item( @@MENU_UPLOAD_COVER )
			add_custom_menu_item( @@MENU_ENTRY_ALBUM )
			add_custom_menu_item( @@MENU_ENTRY_SONG )
		end
		add_custom_checkeable_menu_item( @@MENU_SUBMIT_CONTENT, @wpa_submit )
	end

	def on_quit()
		remove_custom_menu_item( @@MENU_UPLOAD_COVER )
		remove_custom_menu_item( @@MENU_ENTRY_ALBUM )
		remove_custom_menu_item( @@MENU_ENTRY_SONG )
		remove_custom_checkeable_menu_item( @@MENU_SUBMIT_CONTENT )
	end

	def on_custom_menu_item_selected( menu, item, urls )
		return if menu != plugin_name()
		if item == @@MENU_UPLOAD_COVER
			url = URI.parse( urls[0] )
			upload_album_cover( url.scheme == "file" ? URI.decode( url.path ) : nil)
		elsif item == @@MENU_ENTRY_ALBUM
			url = URI.parse( urls[0] )
			return if url.scheme != "file"
			check_album_page( URI.decode( url.path ) )
		elsif item == @@MENU_ENTRY_SONG
			urls.each() do |url|
				# TODO add skip dialog, show remaining
				url = URI.parse( url )
				return if url.scheme != "file"
				check_song_page( URI.decode( url.path ) )
			end
		elsif /\] #{@@MENU_SUBMIT_CONTENT}$/.match( item )
			if ! @wpa_submit && Strings.empty?( @wpa_username ) # there's not username to login with
				@wpa_submit = true
				configure()
				return
			end
			@wpa_submit = ! @wpa_submit
			check_submit_conditions()
			if @wpa_submit
				add_custom_menu_item( @@MENU_UPLOAD_COVER )
				add_custom_menu_item( @@MENU_ENTRY_ALBUM )
				add_custom_menu_item( @@MENU_ENTRY_SONG )
			else
				remove_custom_menu_item( @@MENU_UPLOAD_COVER )
				remove_custom_menu_item( @@MENU_ENTRY_ALBUM )
				remove_custom_menu_item( @@MENU_ENTRY_SONG )
			end
			add_custom_checkeable_menu_item( @@MENU_SUBMIT_CONTENT, @wpa_submit )
		end

	end

	def check_album_page( file )
		album_data = Amarok.query_album_data( file )
		if album_data.empty? || album_data["tracks"].empty? # can't even attempt to search the album...
			notify( I18n.get( "amarok.wikiplugin.checkalbum.noinfofound" ) )
		else
			begin
				tracks = []
				album_data["tracks"].each() do |track|
					tracks << MediaWikiLyrics::TrackData.new( track["artist"], track["title"], track["length"] )
				end
				submit_album_page(
					MediaWikiLyrics::AlbumData.new( tracks, album_data["album"], album_data["year"] ),
					album_data["image_path"],
					false, # is user allowed to overwrite existing pages?
					false, # do we know the page doesn't exists?
					@wpa_review, # should we show the review contents dialog?
					false # should user be forced to review content? (true causes the operation to abort if he doesn't)
				)
			rescue TimeoutError
				notify( I18n.get( "amarok.application.search.plugintimeout", plugin_name(), site_host() ) )
			end
		end
	end


	def upload_album_cover( file )

		album_data = Amarok.query_album_data( file )
		if album_data.empty?
			album_data["artist"] = album_data["album"] = album_data["year"] = album_data["image_path"] = ""
		end
		album_data["site_name"] = site_name()

		if GUI.show_upload_cover_dialog( album_data )

			album_data["year"] = album_data["year"].to_s()
			if Strings.empty?( album_data["artist"] ) || Strings.empty?( album_data["album"] ) || Strings.empty?( album_data["year"] )
				notify( I18n.get( "amarok.wikiplugin.uploadcover.invalidalbumparams" ) )
			elsif Strings.empty?( album_data["image_path"] )
				notify( I18n.get( "amarok.wikiplugin.uploadcover.noimagepath" ) )
			else
				notify( I18n.get( "amarok.wikiplugin.uploadcover.searching", album_data["album"], album_data["artist"] ) )
				begin
					if ! find_album_art_name( album_data["artist"], album_data["album"], album_data["year"] )
						upload_cover_image( album_data["image_path"], album_data["artist"], album_data["album"], album_data["year"])
					else
						notify( I18n.get( "amarok.wikiplugin.uploadcover.found" ) )
					end
				rescue TimeoutError
					notify( I18n.get( "amarok.application.search.plugintimeout", plugin_name(), site_host() ) )
				end
			end
		end

	end

	def wiki_process_response( response, response_plugin, wiki_searched )

		return if ! submit?() || ! authorized?

		lyrics_found_on_site = response.lyrics && response_plugin == self
		lyrics_autogenerated = lyrics_found_on_site && ! response.custom_data["reviewed"]

		return if lyrics_found_on_site && ! lyrics_autogenerated # we have nothing to do
		return if (! @wpa_prompt_autogen && lyrics_autogenerated) || (! @wpa_prompt_no_lyrics && ! response.lyrics)

		begin

			song_data = MediaWikiLyrics::SongData.new(
				response.artist ? response.artist : response.request.artist,
				response.title ? response.title : response.request.title,
				response.lyrics,
				response.album ? response.album : response.request.album,
				response.year ? response.year : response.request.year,
				response.custom_data["credits"],
				response.custom_data["lyricist"]
			)

			url, submitted_data = submit_song_page(
				song_data,
				lyrics_autogenerated ? response.url : nil, # are we editing an existing page or creating a new one?
				song_data.artist == response.request.artist && song_data.title == response.request.title &&
				wiki_searched && ! lyrics_found_on_site, # do we KNOW FOR SURE the page doesn't exists?
				@wpa_review || lyrics_autogenerated, # should we show the review contents dialog?
				lyrics_autogenerated # should user be forced to review contents? (true causes the operation to abort otherwise)
			)

			# transfer summited data to response
			if submitted_data
				response.artist = submitted_data["artist"] if ! Strings.empty?( submitted_data["artist"] )
				response.title = submitted_data["title"] if ! Strings.empty?( submitted_data["title"] )
				response.album = submitted_data["album"] if ! Strings.empty?( submitted_data["album"] )
				response.year = submitted_data["year"] if ! Strings.empty?( submitted_data["year"] )
				response.lyrics = submitted_data["lyrics"] if ! Strings.empty?( submitted_data["lyrics"] )
				custom_data = {}
				custom_data.merge( response.custom_data )
				custom_data["credits"] = submitted_data["credits"] if ! Strings.empty?( submitted_data["credits"] )
				custom_data["lyricst"] = submitted_data["lyricst"] if ! Strings.empty?( submitted_data["lyricst"] )
				response.custom_data = custom_data
			end

		rescue TimeoutError
			notify( I18n.get( "amarok.application.search.plugintimeout", plugin_name(), site_host() ) )
		end

	end

	def check_song_page( file )

		song_data = Amarok.query_song_data( file )

		if song_data.empty?
			notify( I18n.get( "amarok.wikiplugin.checksong.noinfofound" ) )
			return
		end

		request = Lyrics::Request.new( song_data["artist"], song_data["title"], song_data["album"], song_data["year"] )

		notify( I18n.get( "wiki.submitsong.searchingpage", request.title, request.artist ) )

		response = self.lyrics_full_search( request )
		response_plugin = self

		if response.lyrics
			if ! response.custom_data["reviewed"]
				notify( I18n.get( "wiki.submitsong.pagefound.autogenerated", request.title, request.artist ) )
				return if ! @wpa_prompt_autogen # autogen lyrics found but user won't review them, nothing to do for us
			else
				notify( I18n.get( "wiki.submitsong.pagefound", request.title, request.artist ) )
				return # reviewed lyrics found, nothing to do for us
			end
		else
			notify( I18n.get( "wiki.submitsong.nopagefound", request.title, request.artist ) )
		end

		if ! response.lyrics
			# if the lyrics weren't found on the site, first we try to find them in Amarok database
			response.lyrics = Amarok.query_song_lyrics( file )
			response_plugin = nil
			# if we didn't found them there, we try the other selected sites
			if ! response.lyrics
				used_plugins = Plugins.used_plugins().clone()
				used_plugins.delete( self )
				used_plugins.each() do |plugin|
					begin
						response = plugin.lyrics_full_search( request )
						if request.lyrics
							response_plugin = plugin
							break
						end
					rescue TimeoutError
						notify( I18n.get("amarok.application.search.plugintimeout", plugin.plugin_name(), plugin.site_host()) )
					end
				end
			end
		end

		wiki_process_response( response, response_plugin, true )

	end

end
